package compile;

import common.FileUtil;

import java.io.File;
import java.util.UUID;

/**
 * created by YT
 * description: 每次 编译+运行 这个过程，就是下面的一个 task
 * User:lenovo
 * Data:2022-07-17
 * Time:23:34
 */
public class Task {
    // 1. 约定所有临时文件所在的目录
    private String WORK_DIR;

    // 2. 约定代码的类名
    private String CLASS;

    // 3. 约定要编译的代码文件名
    private String CODE;

    // 4. 约定存放编译错误信息的文件名
    private String COMPILE_ERROR;

    // 5. 约定存放标准输出信息的文件名
    private String STDOUT;

    // 6. 约定存放标准错误信息的文件名
    private String STDERR;

    public Task() {
        WORK_DIR = "./tmp/" + UUID.randomUUID().toString() + "/";
        CLASS = "Solution";
        CODE = WORK_DIR + "Solution.java";
        COMPILE_ERROR = WORK_DIR + "compileError.txt";
        STDOUT = WORK_DIR + "stdout.txt";
        STDERR = WORK_DIR + "stderr.txt";
    }
    /**
    * @Author: YT摆渡人
    * @Description: 是task的核心方法， 编译＋运行
    * @DateTime: 2022/7/17 23:37
    * @Params: 要编译的java源代码
    * @Return 编译运行的结果：编译出错/运行出错/运行正确.....
    */
    public Answer compileAndRun(Question question){
        // 让父进程获取到执行的结果，并打包成一个 compile.Answer 并返回
        Answer answer = new Answer();
        // 创建临时目录
        File file = new File(WORK_DIR);
        if (!file.exists()) {
            file.mkdirs();
        }
        // 1. 把question中的code写入到一个临时的 Solution.java 文件
        String content = question.getCode();
        //System.out.println(content);
        FileUtil.writeFile(CODE,content);
        // 2. 创建子进程，调用javac进行编译，编译的时候需要有一个 .java 文件，
        String compileCmd = String.format("javac -encoding utf8 %s -d %s", CODE, WORK_DIR);
        //System.out.println(compileCmd);
        //    如果编译出错，javac就会把错误信息写入到stderr里面，就可以用一个专门的文件来保存，compileError.txt
        CommandUtil.run(compileCmd, null, COMPILE_ERROR);
        // 判断文件内容是否为空
        String compileError = FileUtil.readFile(COMPILE_ERROR);

        if (!"".equals(compileError)) {
            // 编译出错
            // 设置返回结果
            System.out.println("编译出错");
            answer.setError(1);
            answer.setReason(compileError);
            return answer;
        }

        // 3. 创建子进程，调用 java 命令并执行
            String runCmd = String.format("java -classpath %s %s", WORK_DIR, CLASS);
        System.out.println(runCmd);
        // 运行程序的时候，也会把 java 子进程的标准输出和标准错误获取到，放到 stdout.txt 和 stderr.txt
        CommandUtil.run(runCmd, STDOUT, STDERR);
        String runError = FileUtil.readFile(STDERR);
        if (!"".equals(runError)) {
            // 运行错误
            System.out.println("运行出错");
            answer.setError(2);
            answer.setReason(runError);
            return answer;
        }
        // 运行到这里就是编译和运行都成功了
        System.out.println("编译运行成功");
        answer.setError(0);
        answer.setStdout(FileUtil.readFile(STDOUT));

        return answer;
    }

}

